package com.example.wang.bindviewcompiler;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

import java.util.ArrayList;
import java.util.List;

import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;

public class AnnotatedClass {
    /**
     * 类名
     */
    public TypeElement mClassElement;
    /**
     * 成员变量集合类
     */
    public List<BindViewField> mField;
    public List<OnClickMethod> mMethod;
    /**
     * 元素辅助类
     */
    public Elements mElementUtils;
    public AnnotatedClass(TypeElement classElement, Elements elementUtils){
        this.mClassElement = classElement;
        this.mElementUtils = elementUtils;
        this.mField = new ArrayList<>();
        this.mMethod = new ArrayList<>();
    }

    /**
     * 获取正在处理的类的全名
     * @return
     */
    public String getFullClassName(){
        return mClassElement.getQualifiedName().toString();
    }

    /**
     * 添加一个成员
     * @param field
     */
    public void addField(BindViewField field){
        mField.add(field);
    }

    /**
     * 添加方法
     * @param method
     */
    public void addMethod(OnClickMethod method){
        mMethod.add(method);
    }

    /**
     * 输出Java
     * @return
     */
    public JavaFile generateFinder(){
        //构建方法
        MethodSpec.Builder injectMethodBuilder = MethodSpec.methodBuilder("inject")
                .addModifiers(Modifier.PUBLIC)//添加描述
                .addAnnotation(Override.class)//添加注解
                .addParameter(TypeName.get(mClassElement.asType()), "target", Modifier.FINAL)//添加参数
                .addParameter(TypeName.OBJECT, "source")//添加参数
                .addParameter(TypeUtil.FINDER, "finder");//添加参数
        //添加语句
        for (BindViewField field : mField) {
            //添加一行
            injectMethodBuilder.addStatement("target.$N=($T)finder.findView(source,$L)", field.getFieldName()
                    , ClassName.get(field.getFieldType()), field.getResId());
        }
        if (mMethod.size()>0){
            injectMethodBuilder.addStatement("$T listener", TypeUtil.ONCLICK_LISTENER);
        }
        for (OnClickMethod method : mMethod) {
            TypeSpec listener = TypeSpec.anonymousClassBuilder("")
                    .addSuperinterface(TypeUtil.ONCLICK_LISTENER)
                    .addMethod(MethodSpec.methodBuilder("onClick")
                            .addAnnotation(Override.class)
                            .addModifiers(Modifier.PUBLIC)
                            .returns(TypeName.VOID)
                            .addParameter(TypeUtil.ANDROID_VIEW, "view")
                            .addStatement("target.$N()", method.getMethodName())
                            .build())
                    .build();
            injectMethodBuilder.addStatement("listener = $L ", listener);
            for (int id : method.ids) {
                injectMethodBuilder.addStatement("finder.findView(source,$L).setOnClickListener(listener)", id);
            }
        }
        String packageName = getPackageName(mClassElement);
        String className = getClassName(mClassElement, packageName);
        ClassName bindClassName = ClassName.get(packageName, className);
        //构建类
        TypeSpec finderClass = TypeSpec.classBuilder(bindClassName.simpleName() + "$$Injector")//类名
                .addModifiers(Modifier.PUBLIC)//添加描述
                .addSuperinterface(ParameterizedTypeName.get(TypeUtil.INJECTOR, TypeName.get(mClassElement.asType())))//添加接口（类／接口，范型）
                .addMethod(injectMethodBuilder.build())//添加方法
                .build();

        return JavaFile.builder(packageName, finderClass).build();
    }

    /**
     * 获取包名
     * @param type
     * @return
     */
    public String getPackageName(TypeElement type){
        return mElementUtils.getPackageOf(type).getQualifiedName().toString();
    }

    /**
     * 获取类名
     * @param type
     * @param packageName
     * @return
     */
    private static String getClassName(TypeElement type, String packageName){
        int packageLen = packageName.length() + 1;
        return type.getQualifiedName().toString().substring(packageLen).replace('.','$');
    }
}
